In [1]:
import pandas as pd
import numpy as np
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
In [2]:
import warnings
warnings.filterwarnings('ignore')
In [3]:
import plotly

plotly.offline.init_notebook_mode()
In [4]:
df = pd.read_csv(
    'MICRODADOS_ENEM_2019.csv',
    header=0,
    encoding = "ISO-8859-1",
    sep=';',
    skiprows=lambda i: i>0 and np.random.rand() > 0.005,
)

df.head()
Out[4]:
NU_INSCRICAO NU_ANO TP_FAIXA_ETARIA TP_SEXO TP_ESTADO_CIVIL TP_COR_RACA TP_NACIONALIDADE TP_ST_CONCLUSAO TP_ANO_CONCLUIU TP_ESCOLA ... Q016 Q017 Q018 Q019 Q020 Q021 Q022 Q023 Q024 Q025
0 190001595670 2019 4 F 1 1 1 1 2 1 ... B A B B A A E A B B
1 190001692717 2019 11 F 0 1 1 1 8 1 ... A A A B A A C A A A
2 190001133244 2019 7 F 1 2 1 1 3 1 ... A A A B A A B A A B
3 190001123433 2019 6 M 1 3 1 1 2 1 ... A A A C B A D A B B
4 190001692742 2019 4 F 1 1 1 1 3 1 ... B A B B A A D A A B

5 rows × 76 columns

In [5]:
answers = ['TX_RESPOSTAS_CN', 'TX_RESPOSTAS_CH', 'TX_RESPOSTAS_LC', 'TX_RESPOSTAS_MT']
correct_answers = ['TX_GABARITO_CN', 'TX_GABARITO_CH', 'TX_GABARITO_LC', 'TX_GABARITO_MT']
scores = ['NU_NOTA_CN', 'NU_NOTA_CH', 'NU_NOTA_LC', 'NU_NOTA_MT','NU_NOTA_REDACAO']
foreign_language = ['TP_LINGUA']
questions = ['TP_SEXO', 'TP_COR_RACA', 'Q001', 'Q002', 'TP_DEPENDENCIA_ADM_ESC']

df = df[['NU_INSCRICAO']+foreign_language+answers+correct_answers+scores+questions]
In [6]:
df.shape
Out[6]:
(25327, 20)
In [7]:
df['TP_SEXO'].replace({'M': 'Masculino',
                               'F': 'Feminino'}, inplace=True)
df['TP_COR_RACA'].replace({0:'Não declarada',
                                   1:'Branca',
                                   2:'Preta',
                                   3:'Parda',
                                   4:'Amarela',
                                   5:'Indígena'}, inplace=True)
df['Q001'].replace({'A': 'Nunca estudou',
                            'B': 'Fund. incompleto',
                            'C': 'Fund. incompleto', 
                            'D': 'Medio incompleto',
                            'E': 'Medio completo',
                            'F': 'Superior completo',
                            'G': 'Pós graduação',
                            'H': 'Não sabe'}, inplace=True)
df['Q002'].replace({'A': 'Nunca estudou',
                            'B': 'Fund. incompleto',
                            'C': 'Fund. incompleto', 
                            'D': 'Medio incompleto',
                            'E': 'Medio completo',
                            'F': 'Superior completo',
                            'G': 'Pós graduação',
                            'H': 'Não sabe'}, inplace=True)
df['TP_DEPENDENCIA_ADM_ESC'].replace({1: 'Federal',
                         2: 'Estadual',
                         3: 'Municipal',
                         4: 'Privada'}, inplace=True)
In [8]:
df['NU_MEDIA_NOTA'] = df[['NU_NOTA_CN', 'NU_NOTA_CH', 'NU_NOTA_LC', 'NU_NOTA_MT', 'NU_NOTA_REDACAO']].sum(axis=1)/5
In [9]:
df = df[(df['NU_NOTA_LC'] != 0) &
        (df['NU_NOTA_CH'] != 0) & 
        (df['NU_NOTA_CN'] != 0) &
        (df['NU_NOTA_MT'] != 0)]
In [10]:
df['TX_RESPOSTAS_LC'] = df['TX_RESPOSTAS_LC'].str.replace('9', '')
In [11]:
df.loc[df.TP_LINGUA == 0, 'TX_GABARITO_LC'] = df.query('TP_LINGUA ==0')['TX_GABARITO_LC'].str.slice(stop=5)+df['TX_GABARITO_LC'].str.slice(start=10)
df.loc[df.TP_LINGUA == 1, 'TX_GABARITO_LC'] = df['TX_GABARITO_LC'].str.slice(start=5)
In [12]:
df = df.dropna(subset=['TX_RESPOSTAS_CN', 'TX_RESPOSTAS_CH', 'TX_RESPOSTAS_LC', 'TX_RESPOSTAS_MT'])
In [13]:
df['ACERTOS_CN'] = df.apply(lambda x: np.sum(np.array(list(x['TX_RESPOSTAS_CN'])) == np.array(list(x['TX_GABARITO_CN']))), axis=1)
df['ACERTOS_CH'] = df.apply(lambda x: np.sum(np.array(list(x['TX_RESPOSTAS_CH'])) == np.array(list(x['TX_GABARITO_CH']))), axis=1)
df['ACERTOS_LC'] = df.apply(lambda x: np.sum(np.array(list(x['TX_RESPOSTAS_LC'])) == np.array(list(x['TX_GABARITO_LC']))), axis=1)
df['ACERTOS_MT'] = df.apply(lambda x: np.sum(np.array(list(x['TX_RESPOSTAS_MT'])) == np.array(list(x['TX_GABARITO_MT']))), axis=1)
In [14]:
df.dtypes
Out[14]:
NU_INSCRICAO                int64
TP_LINGUA                   int64
TX_RESPOSTAS_CN            object
TX_RESPOSTAS_CH            object
TX_RESPOSTAS_LC            object
TX_RESPOSTAS_MT            object
TX_GABARITO_CN             object
TX_GABARITO_CH             object
TX_GABARITO_LC             object
TX_GABARITO_MT             object
NU_NOTA_CN                float64
NU_NOTA_CH                float64
NU_NOTA_LC                float64
NU_NOTA_MT                float64
NU_NOTA_REDACAO           float64
TP_SEXO                    object
TP_COR_RACA                object
Q001                       object
Q002                       object
TP_DEPENDENCIA_ADM_ESC     object
NU_MEDIA_NOTA             float64
ACERTOS_CN                  int32
ACERTOS_CH                  int32
ACERTOS_LC                  int32
ACERTOS_MT                  int32
dtype: object
In [15]:
df.drop(columns=['TP_LINGUA']).describe()
Out[15]:
NU_INSCRICAO NU_NOTA_CN NU_NOTA_CH NU_NOTA_LC NU_NOTA_MT NU_NOTA_REDACAO NU_MEDIA_NOTA ACERTOS_CN ACERTOS_CH ACERTOS_LC ACERTOS_MT
count 1.829000e+04 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000 18290.000000
mean 1.900035e+11 477.947627 510.265418 522.874921 523.846780 579.262985 522.839546 13.113013 16.882887 18.788300 11.655221
std 1.451021e+06 75.610326 80.169382 61.946249 108.872292 182.855472 83.625224 4.890553 6.941824 7.148045 5.449121
min 1.900010e+11 328.300000 315.900000 323.400000 359.000000 0.000000 290.680000 1.000000 0.000000 1.000000 0.000000
25% 1.900022e+11 418.600000 450.400000 486.000000 435.400000 485.000000 463.840000 10.000000 12.000000 13.000000 8.000000
50% 1.900035e+11 470.000000 514.800000 528.300000 501.700000 580.000000 515.080000 12.000000 16.000000 18.000000 10.000000
75% 1.900047e+11 532.900000 568.300000 566.400000 598.600000 680.000000 576.450000 16.000000 21.000000 24.000000 14.000000
max 1.900061e+11 811.100000 780.600000 718.900000 967.000000 980.000000 806.540000 41.000000 41.000000 41.000000 42.000000
In [16]:
fig = px.histogram(df['NU_NOTA_LC'], color_discrete_sequence=['#f5d86e'])
fig.update_layout(title='Distribuição das notas de Linguagens e Códigos')
In [17]:
fig = px.histogram(df['NU_NOTA_CH'],color_discrete_sequence=['#b46ef5'])
fig.update_layout(title='Distribuição das notas de Ciencias Humanas')
In [18]:
fig = px.histogram(df['NU_NOTA_MT'], color_discrete_sequence=['#6e92f5'])
fig.update_layout(title='Distribuição das notas de Matemática')
In [19]:
fig = px.histogram(df['NU_NOTA_CN'], color_discrete_sequence=['#6ef587'])
fig.update_layout(title='Distribuição das notas de Ciencias da Natureza')
In [20]:
fig = px.histogram(df['NU_NOTA_REDACAO'], color_discrete_sequence=['#f56e6e'])
fig.update_layout(title='Distribuição das notas de Redação')
In [50]:
import statsmodels.api as sm

fig, axes = plt.subplots(3, 2, figsize=(20, 15))

fig = sm.qqplot(df['NU_NOTA_LC'], ax=axes[0,0])
fig = sm.qqplot(df['NU_NOTA_CH'], ax=axes[0,1])
fig = sm.qqplot(df['NU_NOTA_CN'], ax=axes[1,0])
fig = sm.qqplot(df['NU_NOTA_MT'], ax=axes[1,1])
fig = sm.qqplot(df['NU_NOTA_REDACAO'], ax=axes[2,0])


fig.suptitle('Graficos Q-Q para distribuição de notas em cada área de conhecimento', fontsize=16, y = 0.94)
axes[0, 0].set_title('Linguagens')
axes[0, 1].set_title('Ciências Humanas')
axes[1, 0].set_title('Ciências da Natureza')
axes[1, 1].set_title('Matemática')
axes[2, 0].set_title('Redação')

plt.show()
In [49]:
fig, axes = plt.subplots(2, 2, figsize=(20, 15))

sns.scatterplot(x=df['ACERTOS_LC'], y=df['NU_NOTA_LC'], ax=axes[0,0], color='r')
sns.scatterplot(x=df['ACERTOS_CH'], y=df['NU_NOTA_CH'], ax=axes[0,1], color='rebeccapurple')
sns.scatterplot(x=df['ACERTOS_CN'], y=df['NU_NOTA_CN'], ax=axes[1,0], color='g')
sns.scatterplot(x=df['ACERTOS_MT'], y=df['NU_NOTA_MT'], ax=axes[1,1])

fig.suptitle('Intervalo de pontuação de acordo com a quantidade de acertos', fontsize=16, y = 0.94)
axes[0, 0].set_title('Linguagens')
axes[0, 1].set_title('Ciências Humanas')
axes[1, 0].set_title('Ciências da Natureza')
axes[1, 1].set_title('Matemática')

plt.show()
In [23]:
px.histogram(df, x="TP_DEPENDENCIA_ADM_ESC", title='Quantidade de escolas por tipo de administração') 
In [24]:
px.pie(df,"TP_COR_RACA", title='Quantidade de inscritos por raça', hole = 0.7) 
In [25]:
px.box(
df.loc[(~df.TP_DEPENDENCIA_ADM_ESC.isna())], 
x= 'NU_MEDIA_NOTA', color='TP_DEPENDENCIA_ADM_ESC', title='Box plot das notas médias por escola',
category_orders={'TP_DEPENDENCIA_ADM_ESC': ['Estadual', 'Municipal', 'Federal', 'Privada']})
In [26]:
px.box(
df.loc[(~df.Q001.isna())], 
x= 'NU_MEDIA_NOTA', color='Q001', title='Box plot das notas médias por nivel de escolaridade do pai',
category_orders={'Q001': df.loc[(~df.Q001.isna())].groupby("Q001")['NU_MEDIA_NOTA'].mean().sort_values().keys()}
)
In [27]:
px.box(
df.loc[(~df.Q002.isna())], 
x= 'NU_MEDIA_NOTA', color='Q001', title='Box plot das notas médias por nivel de escolaridade da mãe',
category_orders={'Q001': df.loc[(~df.Q002.isna())].groupby("Q002")['NU_MEDIA_NOTA'].mean().sort_values().keys()}
)
In [28]:
fig = px.scatter_matrix(df[scores])
fig.update_layout(height=800, width=1000)
In [29]:
fig = px.scatter(df.loc[df.TP_DEPENDENCIA_ADM_ESC.isin(["Estadual", "Privada"])], x="ACERTOS_MT", y="NU_NOTA_MT", color="TP_DEPENDENCIA_ADM_ESC", trendline="ols")
fig.update_layout(title="Reta de regressão ACERTOS_MT ~ NU_NOTA_MT por tipo de admnistração escolar")
In [30]:
results = px.get_trendline_results(fig)

results.query("TP_DEPENDENCIA_ADM_ESC == 'Estadual'").px_fit_results.iloc[0].summary()
Out[30]:
OLS Regression Results
Dep. Variable: y R-squared: 0.703
Model: OLS Adj. R-squared: 0.703
Method: Least Squares F-statistic: 8715.
Date: Tue, 18 Apr 2023 Prob (F-statistic): 0.00
Time: 07:54:10 Log-Likelihood: -19572.
No. Observations: 3687 AIC: 3.915e+04
Df Residuals: 3685 BIC: 3.916e+04
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 300.4565 2.269 132.431 0.000 296.008 304.905
x1 19.2144 0.206 93.353 0.000 18.811 19.618
Omnibus: 34.770 Durbin-Watson: 1.897
Prob(Omnibus): 0.000 Jarque-Bera (JB): 30.891
Skew: -0.174 Prob(JB): 1.96e-07
Kurtosis: 2.717 Cond. No. 31.3


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [31]:
results = px.get_trendline_results(fig)

results.query("TP_DEPENDENCIA_ADM_ESC == 'Privada'").px_fit_results.iloc[0].summary()
Out[31]:
OLS Regression Results
Dep. Variable: y R-squared: 0.879
Model: OLS Adj. R-squared: 0.879
Method: Least Squares F-statistic: 5629.
Date: Tue, 18 Apr 2023 Prob (F-statistic): 0.00
Time: 07:54:10 Log-Likelihood: -3995.8
No. Observations: 776 AIC: 7996.
Df Residuals: 774 BIC: 8005.
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
const 384.4623 3.649 105.359 0.000 377.299 391.626
x1 14.5391 0.194 75.029 0.000 14.159 14.919
Omnibus: 55.802 Durbin-Watson: 1.491
Prob(Omnibus): 0.000 Jarque-Bera (JB): 66.141
Skew: -0.704 Prob(JB): 4.34e-15
Kurtosis: 3.256 Cond. No. 46.0


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [32]:
df_corr = df[scores].corr(
    method = 'pearson'
)

sns.heatmap(df_corr, annot=True)
plt.title("Matriz de correlação entre as notas das áreas de conhecimento")
plt.show()
In [38]:
crosstab=pd.crosstab(index=df['Q001'],columns=df['Q002'], normalize='columns', margins=True)
In [39]:
crosstab
Out[39]:
Q002 Fund. incompleto Medio completo Medio incompleto Nunca estudou Não sabe Pós graduação Superior completo All
Q001
Fund. incompleto 0.649297 0.240911 0.369186 0.312727 0.102450 0.115269 0.129281 0.345216
Medio completo 0.107589 0.429250 0.246262 0.040000 0.102450 0.288473 0.346840 0.274576
Medio incompleto 0.088171 0.121028 0.236296 0.036364 0.040089 0.080266 0.084419 0.114762
Nunca estudou 0.073905 0.015558 0.026993 0.547273 0.026726 0.006639 0.005306 0.047458
Não sabe 0.064197 0.073043 0.079319 0.060000 0.688196 0.038021 0.055958 0.081028
Pós graduação 0.004557 0.030953 0.011628 0.000000 0.015590 0.286059 0.114327 0.052378
Superior completo 0.012285 0.089256 0.030316 0.003636 0.024499 0.185275 0.263869 0.084582
In [45]:
from scipy.stats import chi2_contingency

# H0: two groups have no significant difference
# alfa = 0.05
result = chi2_contingency(pd.crosstab(index=df['Q001'],columns=df['Q002']))
In [48]:
print(f"O teste qui-quadrado de independência de variáveis em uma tabela de contingência teve valor igual a {result[0]} e p-valor igual a {result[1]}. Logo, podemos rejeitar a hipotese nula e portanto temos diferença entre os grupos.") 
O teste qui-quadrado de independência de variáveis em uma tabela de contingência teve valor igual a 12938.808193005201 e p-valor igual a 0.0. Logo, podemos rejeitar a hipotese nula e portanto temos diferença entre os grupos.
In [ ]:
 
In [ ]: